package com.platform.oss.core.minio;

import cn.hutool.core.io.IoUtil;
import com.google.common.io.ByteStreams;
import com.platform.comm.util.StringPool;
import com.platform.comm.util.StringUtil;
import com.platform.oss.core.minio.model.MinioOssConfig;
import com.platform.oss.exception.OssException;
import com.platform.oss.core.StandardOssClient;
import io.minio.BucketExistsArgs;
import io.minio.GetObjectArgs;
import io.minio.GetObjectResponse;
import io.minio.MakeBucketArgs;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.RemoveObjectArgs;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import java.io.InputStream;
import java.io.OutputStream;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Data
@AllArgsConstructor
@NoArgsConstructor
public class MinioOssClient implements StandardOssClient {

    public static final String MINIO_OBJECT_NAME = "minioClient";

    private MinioClient minioClient;
    private MinioOssConfig minioOssConfig;

    @Override
    public String upload(InputStream is, String fileName) {
        log.info("minio upload :::::::::::");
        return this.uploadFile(is,fileName.substring(fileName.lastIndexOf(".") + 1));
    }

    /**
     * 对象上传
     *
     * @param is     对象流
     * @param suffix 文件后缀
     * @return 返回存储对象的id
     */
    @SneakyThrows
    public String uploadFile(InputStream is, String suffix) {
        // 上传文件名处理
        String filename = StringUtil.getUUID();
        if (suffix.startsWith(StringPool.DOT)) {
            filename += suffix;
        } else {
            filename += StringPool.DOT + suffix;
        }
        // 不再支持创建包含大写字母或下划线的bucket名称
        createBucket(minioOssConfig.getBucketName());
        // 文件存储路径处理，根据时间，尽量让上传文件正态分布
        LocalDateTime time = LocalDateTime.now();
        String hex = Integer.toHexString(time.hashCode()).toUpperCase();
        String tmp = StringUtils.rightPad(hex, 8, '0');
        // + "/" + tmp.substring(6, 8);
        String path = tmp.substring(0, 2) + "/" + tmp.substring(2, 4) + "/" + tmp.substring(4, 6);
        String objectName = path + "/" + filename;
        putObject(minioOssConfig.getBucketName(), objectName, is);
        return objectName;
    }
    /**
     * 上传文件
     *
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @param stream     文件流
     * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#putObject
     */
    public void putObject(String bucketName, String objectName, InputStream stream) throws Exception {
        minioClient.putObject(PutObjectArgs.builder().bucket(bucketName)
                .object(objectName).stream(stream, stream.available(), -1)
                .contentType("application/octet-stream").build());
    }

    /**
     * 创建bucket
     *
     * @param name bucket名称
     */
    @SneakyThrows
    public void createBucket(String name) {
        BucketExistsArgs args = BucketExistsArgs.builder().bucket(name).build();
        MakeBucketArgs makeBucketArgs = MakeBucketArgs.builder().bucket(name).build();
        if (!minioClient.bucketExists(args)) {
            minioClient.makeBucket(makeBucketArgs);
        }
    }

    /**
     * 对象下载
     *
     * @param fileId 对象id
     * @return 返回存储对象的流
     */
    @Override
    public InputStream download(String fileId) {
        log.info("minio download :::::::::::");
        return getObject(minioOssConfig.getBucketName(), fileId);
    }
    /**
     * 获取文件
     *
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @return 二进制流
     */
    @SneakyThrows
    public InputStream getObject(String bucketName, String objectName) {
        return minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build());
    }

    @Override
    public void downLoad(OutputStream os, String targetName) {
        GetObjectResponse is = null;
        try {
            GetObjectArgs getObjectArgs = GetObjectArgs.builder()
                    .bucket(getBucket())
                    .object(getKey(targetName, true))
                    .build();
            is = minioClient.getObject(getObjectArgs);
            ByteStreams.copy(is, os);
        } catch (Exception e) {
            throw new OssException(e);
        } finally {
            IoUtil.close(is);
        }
    }

    @Override
    public void delete(String targetName) {
        try {
            RemoveObjectArgs removeObjectArgs = RemoveObjectArgs.builder()
                    .bucket(getBucket())
                    .object(getKey(targetName, true))
                    .build();
            minioClient.removeObject(removeObjectArgs);
        } catch (Exception e) {
            throw new OssException(e);
        }
    }

    @Override
    public String getBasePath() {
        return minioOssConfig.getBasePath();
    }

    public Map<String, Object> getClientObject() {
        return new HashMap<String, Object>() {
            {
                put(MINIO_OBJECT_NAME, getMinioClient());
            }
        };
    }

    private String getBucket() {
        return minioOssConfig.getBucketName();
    }

}
